package com.zqxq.lottery.service.order.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.gson.JsonObject;
import com.zqxq.common.constant.Result;
import com.zqxq.common.enums.CodeEnum;
import com.zqxq.common.utils.BigDecimalUtils;
import com.zqxq.common.utils.DispatcherUtils;
import com.zqxq.common.utils.JsonUtils;
import com.zqxq.common.utils.StrUtils;
import com.zqxq.lottery.common.utils.FootBallBetUtils;
import com.zqxq.lottery.config.YmlConfig;
import com.zqxq.lottery.entity.bo.order.UserOrderBO;
import com.zqxq.lottery.entity.bo.order.UserOrderBetBO;
import com.zqxq.lottery.entity.enums.LotteryIdEnum;
import com.zqxq.lottery.entity.o2o.order.OrderTicketO2O;
import com.zqxq.lottery.entity.o2o.order.UserOrderBetO2O;
import com.zqxq.lottery.entity.o2o.order.UserOrderO2O;
import com.zqxq.lottery.entity.o2o.user.UserInfoO2O;
import com.zqxq.lottery.entity.po.export.ExpertInfoPO;
import com.zqxq.lottery.entity.po.jczq.JczqWorldCupPO;
import com.zqxq.lottery.entity.po.order.*;
import com.zqxq.lottery.entity.po.sys.LotteryHnumPO;
import com.zqxq.lottery.entity.po.user.*;
import com.zqxq.lottery.entity.vo.esports.ESportsPlaywayVO;
import com.zqxq.lottery.entity.vo.esports.ESportsVO;
import com.zqxq.lottery.entity.vo.jczq.JczqMatchLiveVO;
import com.zqxq.lottery.entity.vo.jczq.JczqMatchVO;
import com.zqxq.lottery.entity.vo.order.PushOrderDetailVO;
import com.zqxq.lottery.entity.vo.order.UserOrderBetVO;
import com.zqxq.lottery.entity.vo.order.UserOrderVO;
import com.zqxq.lottery.entity.vo.user.UserPrizeVO;
import com.zqxq.lottery.mapper.expert.ExpertInfoMapper;
import com.zqxq.lottery.mapper.jczq.JczqWorldCupMapper;
import com.zqxq.lottery.mapper.order.*;
import com.zqxq.lottery.mapper.sys.LotteryHnumMapper;
import com.zqxq.lottery.mapper.user.*;
import com.zqxq.lottery.mq.Sender;
import com.zqxq.lottery.service.esports.IESportsPlaywayService;
import com.zqxq.lottery.service.esports.IESportsService;
import com.zqxq.lottery.service.expert.IExpertInfoService;
import com.zqxq.lottery.service.jczq.IJczqMatchResultService;
import com.zqxq.lottery.service.jczq.IJczqMatchService;
import com.zqxq.lottery.service.order.IFollowOrderService;
import com.zqxq.lottery.service.order.IUserOrderService;
import com.zqxq.lottery.service.sys.ISysActivityService;
import com.zqxq.lottery.service.user.IUserFundsService;
import com.zqxq.lottery.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;


@Service
@Slf4j
public class UserOrderServiceImpl extends ServiceImpl<UserOrderMapper, UserOrderPO> implements IUserOrderService {
    @Autowired
    private YmlConfig ymlConfig;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private UserOrderBetMapper userOrderBetMapper;
    @Autowired
    private UserOrderBetBopMapper userOrderBetBopMapper;
    @Autowired
    private OrderTicketMapper orderTicketMapper;
    @Autowired
    private LotteryHnumMapper lotteryHnumMapper;
    @Autowired
    private UserFundsMapper userFundsMapper;
    @Autowired
    private UserCashMapper userCashMapper;
    @Autowired
    private CalculatorSSQ calculatorSSQ;
    @Autowired
    private CalculatorDLT calculatorDLT;
    @Autowired
    private CalculatorFC calculatorFC;
    @Autowired
    private CalculatorPL calculatorPL;
    @Autowired
    private CalculatorQXC calculatorQXC;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private IJczqMatchResultService jczqMatchResultService;
    @Autowired
    private JczqWorldCupMapper jczqWorldCupMapper;
    @Autowired
    private UserOrderMapper userOrderMapper;
    @Autowired
    private FollowOrderMapper followOrderMapper;
    @Autowired
    private ISysActivityService sysActivityService;
    @Autowired
    private Sender sender;
    @Autowired
    private UserPrizeMapper userPrizeMapper;
    @Autowired
    private IFollowOrderService followOrderService;
    @Autowired
    private IExpertInfoService expertInfoService;
    @Autowired
    private IUserFundsService userFundsService;
    @Autowired
    private IESportsService eSportsService;
    @Autowired
    private IESportsPlaywayService eSportsPlaywayService;
    @Autowired
    private ExpertInfoMapper expertInfoMapper;
    @Autowired
    private RobotOrderDataMapper robotOrderDataMapper;
    @Autowired
    private IJczqMatchService jczqMatchService;

    @Override
    public Page queryPage(UserOrderBO search) throws Exception {
        Page page = new Page(search.getPageNo(), search.getPageSize());
        List<UserOrderVO> list = baseMapper.queryPage(page, search);
        for(UserOrderVO userOrderVO : list){
            if("21".equals(userOrderVO.getLotteryId())){
                userOrderVO.setLotteryName("竞猜足球");
            }else if("24".equals(userOrderVO.getLotteryId())){
                userOrderVO.setLotteryName("竞猜篮球");
            }else if("10".equals(userOrderVO.getLotteryId())){
                ESportsVO eSportsVO = eSportsService.getESportsById(userOrderVO.getPeriod());
                //1:LOL 2:DOTA2 3:CSGO 4:守望先锋 5:篮球 6:足球 7:王者荣耀 8:绝地求生 9:魔兽争霸3 10:炉石传说 11:彩虹6号  12:星际争霸1 13:星际争霸2 14:风暴英雄 15:堡垒之夜 16:FIFA Online 17:穿越火线 18:传说对决 19:使命召唤 20:火箭联盟 21:NBA2K
                if ("1".equals(eSportsVO.getType())) {
                    userOrderVO.setLotteryName("LOL");
                } else if ("2".equals(eSportsVO.getType())) {
                    userOrderVO.setLotteryName("DOTA2");
                } else if ("3".equals(eSportsVO.getType())) {
                    userOrderVO.setLotteryName("CSGO");
                } else if ("4".equals(eSportsVO.getType())) {
                    userOrderVO.setLotteryName("守望先锋");
                } else if ("5".equals(eSportsVO.getType())) {
                    userOrderVO.setLotteryName("篮球");
                } else if ("6".equals(eSportsVO.getType())) {
                    userOrderVO.setLotteryName("足球");
                } else if ("7".equals(eSportsVO.getType())) {
                    userOrderVO.setLotteryName("王者荣耀");
                } else if ("8".equals(eSportsVO.getType())) {
                    userOrderVO.setLotteryName("绝地求生");
                }
            }
        }
        page.setRecords(list);
        return page;
    }

    @Override
    public Page queryPageApp(UserOrderBO search) throws Exception {
        //未支付过了支付截止时间的订单自动取消
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("user_id",search.getUserId());
        wrapper.eq("status",0);
        wrapper.lt("lottery_time",new Date());
        List<UserOrderPO> userOrderPOList = baseMapper.selectList(wrapper);
        for(UserOrderPO userOrderPO : userOrderPOList){
            userOrderPO.setStatus(11);
            baseMapper.updateById(userOrderPO);
        }
        //未中奖订单超过1周自动隐藏
        List<String> orderIds = baseMapper.queryNotWinMoreThanWeeks(search.getUserId());
        for(String orderId : orderIds){
            UserOrderPO po = baseMapper.selectById(orderId);
            po.setStatus(10);
            baseMapper.updateById(po);
        }
        Page page = new Page(search.getPageNo(), search.getPageSize());
        List<UserOrderVO> list = baseMapper.queryPageApp(page, search);
        page.setRecords(list);
        return page;
    }

    @Override
    public Result queryDJPageApp(UserOrderBO search) throws Exception {
        Result result = new Result();
        //未支付过了支付截止时间的订单自动取消
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("user_id",search.getUserId());
        wrapper.eq("status",0);
        wrapper.lt("lottery_time",new Date());
        List<UserOrderPO> userOrderPOList = baseMapper.selectList(wrapper);
        for(UserOrderPO userOrderPO : userOrderPOList){
            userOrderPO.setStatus(11);
            baseMapper.updateById(userOrderPO);
        }
        //未中奖订单超过1周自动隐藏
        List<String> orderIds = baseMapper.queryNotWinMoreThanWeeks(search.getUserId());
        for(String orderId : orderIds){
            UserOrderPO po = baseMapper.selectById(orderId);
            po.setStatus(10);
            baseMapper.updateById(po);
        }
        Page page = new Page(search.getPageNo(), search.getPageSize());
        List<UserOrderVO> list = baseMapper.queryPageApp(page, search);
        for(UserOrderVO vo : list){
            List<UserOrderBetPO> userOrderBetPOList = userOrderBetMapper.selectOrderBetList(Long.valueOf(vo.getId()),10L);
            UserOrderBetPO userOrderBetPO = userOrderBetPOList.get(0);
            String redNum = userOrderBetPO.getRed_num();
            String period = userOrderBetPO.getPeriod();
            ESportsVO eSportsVO = eSportsService.getESportsById(period);
            String playType = String.valueOf(userOrderBetPO.getPlay_type());
            ESportsPlaywayVO eSportsPlaywayVO = eSportsPlaywayService.getESportsPlayway(period,playType);
            vo.setDjPlayDescribe(eSportsPlaywayVO.getPlayName());
            if(!StringUtils.isEmpty(redNum)){
                Map<String,Object> playsMap = JSONObject.parseObject(eSportsPlaywayVO.getPlayOdds(),Map.class);
                Map<String,Object> playMap = JSONObject.parseObject(JSONObject.toJSONString(playsMap.get(redNum)),Map.class);
                String partName = (String) playMap.get("partName");
                vo.setDjSelectTeam(partName);
            }
            String matchName = null;
            if ("1".equals(eSportsVO.getType())) {
                matchName = "LOL";
            } else if ("2".equals(eSportsVO.getType())) {
                matchName = "DOTA2";
            } else if ("3".equals(eSportsVO.getType())) {
                matchName = "CSGO";
            } else if ("4".equals(eSportsVO.getType())) {
                matchName = "守望先锋";
            } else if ("5".equals(eSportsVO.getType())) {
                matchName = "篮球";
            } else if ("6".equals(eSportsVO.getType())) {
                matchName = "足球";
            } else if ("7".equals(eSportsVO.getType())) {
                matchName = "王者荣耀";
            } else if ("8".equals(eSportsVO.getType())) {
                matchName = "绝地求生";
            }
            vo.setDjMatchName(matchName);
        }
        Map<String,Object> map = baseMapper.queryOrderStatistics(search.getUserId());
        page.setRecords(list);
        Map<String,Object> resultMap = new HashMap();
        resultMap.put("page",page);
        resultMap.put("competitionNumber",map.get("competitionNumber"));
        resultMap.put("winnProbability",map.get("winnProbability"));
        resultMap.put("totalIncome",map.get("totalIncome"));
        result.setData(resultMap);
        return result;
    }

    @Override
    public UserOrderVO get(Long id) throws Exception {
        UserOrderVO vo = new UserOrderVO();
        UserOrderPO po = baseMapper.selectById(id);
        log.info("***********************************************************************");
        log.info("po:"+ JsonUtils.stringify(po));
        if (null != po) {
            vo = UserOrderO2O.toVO(po);
            log.info("vo:"+ JsonUtils.stringify(vo));
            log.info("***********************************************************************");
            UserInfoPO userPO = userInfoMapper.selectById(po.getUser_id());
            UserOrderBetBO search = new UserOrderBetBO();
            search.setOrderId(id);
            search.setLotteryId(po.getLottery_id());
            List<UserOrderBetVO> betList = userOrderBetMapper.queryList(search);
            Wrapper wrapper = new EntityWrapper();
            wrapper.eq("order_id", id);
            List<OrderTicketPO> ticketList = orderTicketMapper.selectList(wrapper);
            vo.setUserInfo(UserInfoO2O.toVO(userPO));
            if("21".equals(vo.getLotteryId())){
                Map<String,Object> map = jczqMatchResultService.getBetInfo(vo.getId());
                JSONArray orderBetJson = (JSONArray) map.get("resultList");
                String expectedBonus = String.valueOf(map.get("expectedBonus"));
                vo.setExpectedBonus(expectedBonus);
                vo.setOrderBetJson(orderBetJson.toString());
                vo.setOrderBetList(betList);
            }
            else if("210".equals(vo.getLotteryId())){
                getBetInfo_210(vo,po,betList);
            }else{
                LotteryHnumPO lotteryHnumPO = new LotteryHnumPO();
                lotteryHnumPO.setLottery_id(po.getLottery_id());
                lotteryHnumPO.setPeriod(po.getPeriod());
                lotteryHnumPO = lotteryHnumMapper.selectOne(lotteryHnumPO);
                String lotteryNum = null;
                if(lotteryHnumPO!=null && lotteryHnumPO.getRed_num()!=null){
                    lotteryNum = lotteryHnumPO.getRed_num()+"|"+lotteryHnumPO.getBlue_num();
                }
                vo.setLotteryNum(lotteryNum);
                vo.setOrderBetList(betList);
            }
            vo.setTicketList(OrderTicketO2O.toVOList(ticketList));
        }
        return vo;
    }


    @Override
    public UserOrderVO getH5(Long id) throws Exception {
        UserOrderVO vo = new UserOrderVO();
        UserOrderPO po = baseMapper.selectById(id);
        if (null != po) {
            vo = UserOrderO2O.toVO(po);
            UserOrderBetBO search = new UserOrderBetBO();
            search.setOrderId(id);
            search.setLotteryId(po.getLottery_id());
            List<UserOrderBetVO> betList = userOrderBetMapper.queryList(search);
            if("21".equals(vo.getLotteryId())){
                Map<String,Object> map = jczqMatchResultService.getBetInfo(vo.getId());
                JSONArray orderBetJson = (JSONArray) map.get("resultList");
                String expectedBonus = String.valueOf(map.get("expectedBonus"));
                vo.setExpectedBonus(expectedBonus);
                vo.setOrderBetList(betList);
                //判断用户订单是否为跟单 再根据推单展示权限进行详情投注展示
                Integer follow_status = po.getFollow_status();
                if (follow_status == 1 && po.getFollow_order_id() != null){
                    //跟单
                    PushOrderDetailVO pushOrderDetailVO = followOrderMapper.getPushOrderDetailByPid(po.getFollow_order_id().toString());
                    if (pushOrderDetailVO == null)
                        return null;
                    packagePushOrderByUserId(pushOrderDetailVO.getExpertId(),pushOrderDetailVO);
                    //判断跟单所选场次是否全部开赛 isOpen：1 全部开赛 0：未全部开赛
//                    Integer openStatus = pushOrderDetailVO.getOpenStatus();
//                    int isOpen = baseMapper.queryIsAllOpen(vo.getId());
//                    if ((openStatus == 0 && isOpen == 1) || (openStatus == 1 && (po.getStatus() >= 3 && po.getStatus() <= 6))){
                        vo.setOrderBetJson(orderBetJson.toString());
//                    }
                    //订单中奖 计算支付的佣金、盈利率
                    pushOrderDetailVO.setProfitOdds("0");//盈利率
                    pushOrderDetailVO.setCommission("0");
                    if (po.getStatus() >= 4 && po.getStatus() <= 6){
                        UserCashPO userCashPO = new UserCashPO();
                        userCashPO.setUser_id(po.getUser_id());
                        userCashPO.setType(6);
                        userCashPO.setPay_account(id.toString());
                        userCashPO = userCashMapper.selectOne(userCashPO);
                        BigDecimal profitAmount = new BigDecimal(0);
                        if (userCashPO != null){
                            profitAmount = userCashPO.getPay_amount();
                        }
                        pushOrderDetailVO.setCommission(String.valueOf(profitAmount.setScale(2,BigDecimal.ROUND_HALF_UP).abs()));//佣金
                        NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
                        percent.setMaximumFractionDigits(2); //百分比小数点最多3位
                        BigDecimal subtract = po.getPrize().subtract(po.getPay_amount()).subtract(profitAmount.abs());
                        //盈利率
                        String podd = String.valueOf(subtract.divide(po.getPay_amount(), 2, BigDecimal.ROUND_HALF_UP));
                        podd = podd.replace(",","");
                        pushOrderDetailVO.setProfitOdds(podd);
                    }
                    vo.setSecrecySet("3");
                    vo.setPushOrderDetailVO(pushOrderDetailVO);
                }else if(follow_status == 2){
                    //推单
                    vo.setOrderBetJson(orderBetJson.toString());
                    PushOrderDetailVO pushOrderDetailVO = followOrderMapper.getPushOrderDetailByPid(po.getId().toString());
                    if (pushOrderDetailVO == null){
                        pushOrderDetailVO = new PushOrderDetailVO();
                    }
                    packagePushOrderByUserId(pushOrderDetailVO.getExpertId(),pushOrderDetailVO);
                    NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
                    percent.setMaximumFractionDigits(2); //百分比小数点最多3位
                    pushOrderDetailVO.setProfitOdds("0");//盈利率
                    pushOrderDetailVO.setCommission("0");
                    //佣金
                    if (po.getStatus() >= 4 && po.getStatus() <= 6){
                        BigDecimal prizeOdds = (po.getPrize().subtract(po.getPay_amount())).divide(po.getPay_amount(),2,BigDecimal.ROUND_HALF_UP);
                        String profitOdd = String.valueOf(prizeOdds).replace(",","");
                        profitOdd = profitOdd.replace(",","");
                        pushOrderDetailVO.setProfitOdds(profitOdd);//盈利率
                        if (prizeOdds.compareTo(new BigDecimal(0.1)) == -1){
                            //中奖奖金收益低于10%不收佣金
                            vo.setWarning("中奖奖金收益低于10%不收佣金");
                            pushOrderDetailVO.setCommission("0");
                        }else{
                            UserCashPO userCashPO = new UserCashPO();
                            userCashPO.setUser_id(po.getUser_id());
                            userCashPO.setType(6);
                            userCashPO.setPay_account(id.toString());
                            userCashPO = userCashMapper.selectOne(userCashPO);
                            BigDecimal profitAmount = new BigDecimal(0);
                            if (userCashPO != null){
                                profitAmount = userCashPO.getPay_amount();
                            }
                            pushOrderDetailVO.setCommission(String.valueOf(profitAmount.setScale(2,BigDecimal.ROUND_HALF_UP).abs()));//佣金
                        }
                    }
                    vo.setPushOrderDetailVO(pushOrderDetailVO);
                }
                else {
                    vo.setOrderBetJson(orderBetJson.toString());
                }
            }
            else if("210".equals(vo.getLotteryId())) {
                getBetInfo_210(vo, po, betList);
            }else if("10".equals(vo.getLotteryId())){
                getBetInfo_10(vo, po, betList);
            }else if("24".equals(vo.getLotteryId())){
                getBetInfo_24(vo, po, betList);
            }else{
                LotteryHnumPO lotteryHnumPO = new LotteryHnumPO();
                lotteryHnumPO.setLottery_id(po.getLottery_id());
                lotteryHnumPO.setPeriod(po.getPeriod());
                lotteryHnumPO = lotteryHnumMapper.selectOne(lotteryHnumPO);
                String lotteryNum = null;
                if(lotteryHnumPO!=null && lotteryHnumPO.getRed_num()!=null){
                    lotteryNum = lotteryHnumPO.getRed_num()+"|"+lotteryHnumPO.getBlue_num();
                }
                vo.setLotteryNum(lotteryNum);
                vo.setOrderBetList(betList);
            }
        }
        return vo;
    }

    private void packagePushOrderByUserId(String userId, PushOrderDetailVO pushOrderDetailVO) {
        //包装跟单数据
        if (userId.split(",").length>1){
            userId = userId.split(",")[0];
        }
        ExpertInfoPO expertInfoPO = new ExpertInfoPO();
        expertInfoPO.setUser_id(Long.valueOf(userId));
        expertInfoPO.setType(1);
        expertInfoPO = expertInfoMapper.selectOne(expertInfoPO);
        if (expertInfoPO != null){
            Integer follows = pushOrderDetailVO.getFollows();
            BigDecimal followAmt = pushOrderDetailVO.getFollowAmt();
            String f = stringRedisTemplate.opsForValue().get("ROBOT" + pushOrderDetailVO.getOrderId());
            if (StrUtils.isNotEmpty(f)){
                Integer intF = Integer.valueOf(f);
                follows+=intF;
                BigDecimal minFollowAmt = pushOrderDetailVO.getMinFollowAmt();
                followAmt = followAmt.add(minFollowAmt.multiply(new BigDecimal(intF)));
            }else {
                List<Integer> l = Arrays.asList(3,4,5,6,10);
                if (l.contains(pushOrderDetailVO.getFollowOrderStatus())){
                    RobotOrderDataPO robotOrderDataPO = new RobotOrderDataPO();
                    robotOrderDataPO.setOrder_id(Long.valueOf(pushOrderDetailVO.getOrderId()));
                    robotOrderDataPO = robotOrderDataMapper.selectOne(robotOrderDataPO);
                    if (robotOrderDataPO != null){
                        BigDecimal follow_amt = robotOrderDataPO.getFollow_amt();
                        Integer fo = robotOrderDataPO.getFollows();
                        follows+=fo;
                        followAmt = followAmt.add(follow_amt);
                    }

                }
            }
            pushOrderDetailVO.setFollows(follows);
            pushOrderDetailVO.setFollowAmt(followAmt);
        }
    }

    private void getBetInfo_10(UserOrderVO vo, UserOrderPO po, List<UserOrderBetVO> betList){
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("period", vo.getPeriod());
        String period = vo.getPeriod();
        ESportsVO eSportsVO = eSportsService.getESportsById(period);
        UserOrderBetVO userOrderBetVO = betList.get(0);
        String playType = userOrderBetVO.getPlayType();
        ESportsPlaywayVO eSportsPlaywayVO = eSportsPlaywayService.getESportsPlayway(period,playType);
        JSONObject jsonObject = new JSONObject();
        if(eSportsVO!=null && eSportsPlaywayVO!=null){
            jsonObject.put("matchName",eSportsVO.getMatchName());
            jsonObject.put("round","BO"+eSportsVO.getRound());
            jsonObject.put("rounds",eSportsPlaywayVO.getRound());
            jsonObject.put("type",eSportsVO.getType());
            jsonObject.put("leftTeamLogo",eSportsVO.getLeftTeamLogo());
            jsonObject.put("rightTeamLogo",eSportsVO.getRightTeamLogo());
            jsonObject.put("leftTeam",eSportsVO.getLeftTeam());
            jsonObject.put("rightTeam",eSportsVO.getRightTeam());
            jsonObject.put("status",eSportsPlaywayVO.getStatus());
            String betDescribe = null;
            String betOdds = null;
            String playDescribe = eSportsPlaywayVO.getPlayName();
            String redNum = userOrderBetVO.getRedNum();
            String blueNum = userOrderBetVO.getBlueNum();
            if(!StringUtils.isEmpty(redNum)){
                Map<String,Object> playsMap = JSONObject.parseObject(eSportsPlaywayVO.getPlayOdds(),Map.class);
                Map<String,Object> playMap = JSONObject.parseObject(JSONObject.toJSONString(playsMap.get(redNum)),Map.class);
                betDescribe = (String) playMap.get("partName");
                betOdds = (String) playMap.get("partOdds");
            }
            jsonObject.put("playDescribe",playDescribe);
            jsonObject.put("betDescribe",betDescribe);
            jsonObject.put("betOdds",blueNum);
        }
        vo.setOrderBetList(betList);
        vo.setOrderBetJson(jsonObject.toString());
    }

    private void getBetInfo_24(UserOrderVO vo, UserOrderPO po, List<UserOrderBetVO> betList){
        JSONArray resultList = new JSONArray();
        String expectedBonus = "";
        try {
            List<UserOrderBetPO> OrderBetList = userOrderBetMapper.selectOrderBetList(Long.valueOf(vo.getId()),24L);
            UserOrderPO userOrderPO = userOrderMapper.selectById(vo.getId());
            List<Double[]> list = new ArrayList();
            for (UserOrderBetPO orderBet : OrderBetList) {
                JSONObject resultMap = new JSONObject();
                JczqMatchVO jczqMatchVO = jczqMatchService.get(orderBet.getPeriod());
                String redNum = orderBet.getRed_num();
                JczqMatchLiveVO jczqMatchResultVO = jczqMatchResultService.get(Long.valueOf(orderBet.getPeriod()));
                resultMap.put("matchResult",jczqMatchResultVO.getResult());
                resultMap.put("matchResultInfo",jczqMatchResultVO.getInfo());
                if(!ObjectUtils.isEmpty(jczqMatchVO)){
                    resultMap.put("playType",orderBet.getPlay_type());
                    resultMap.put("matchCode",jczqMatchVO.getCode());
                    resultMap.put("matchField",jczqMatchVO.getMatchField());
                    resultMap.put("hostTeam",jczqMatchVO.getHostTeam());
                    resultMap.put("guestTeam",jczqMatchVO.getGuestTeam());
                    resultMap.put("letNum",jczqMatchVO.getScore());
                    resultMap.put("totalScore",jczqMatchVO.getTotalScore());
                    String[] redNums = orderBet.getRed_num().split("\\,");
                    List<Map<String,Object>> betList2 = new ArrayList();
                    Map<String,String> oddsMap = new HashMap();
                    for (int i=0;i<redNums.length;i++) {
                        Map<String,Object> matchMap = new HashMap();
                        matchMap.put("betNum",redNums[i]);
                        matchMap.put("odds",orderBet.getBlue_num().split("\\,")[i]);
                        betList2.add(matchMap);
                        oddsMap.put(redNums[i],orderBet.getBlue_num().split("\\,")[i]);
                    }
                    resultMap.put("betList",betList2);
                    Double[] m1 = FootBallBetUtils.getMinMaxOdds(redNum,oddsMap);
                    list.add(m1);
                }

                resultList.add(resultMap);
            }
            Double minBonus = FootBallBetUtils.betMinVal(userOrderPO.getBet_bunch().split(","), list);
            Double maxBonus = FootBallBetUtils.betMaxVal(userOrderPO.getBet_bunch().split(","), list);
            BigDecimal min = new BigDecimal(minBonus).multiply(new BigDecimal(userOrderPO.getBet_times())).setScale(2,BigDecimal.ROUND_HALF_UP);
            BigDecimal max = new BigDecimal(maxBonus).multiply(new BigDecimal(userOrderPO.getBet_times())).setScale(2,BigDecimal.ROUND_HALF_UP);
            if(userOrderPO.getIs_bonus_optimize()!=null && userOrderPO.getIs_bonus_optimize()==0){
                Wrapper wrapper = new EntityWrapper();
                wrapper.eq("order_id",vo.getId());
                List<UserOrderBetBopPO> userOrderBetBopPOS = userOrderBetBopMapper.selectList(wrapper);
                SelfStringUtils.sortByAttribute(userOrderBetBopPOS);
                BigDecimal totalExpectBonus = BigDecimal.ZERO;
                for(UserOrderBetBopPO userOrderBetBopPO : userOrderBetBopPOS){
                    totalExpectBonus = totalExpectBonus.add(userOrderBetBopPO.getExpect_bonus());
                }
                expectedBonus = userOrderBetBopPOS.get(0).getExpect_bonus() + "~" + totalExpectBonus;
            }else {
                expectedBonus = String.valueOf(min) + "~" + String.valueOf(max);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        vo.setExpectedBonus(expectedBonus);
        vo.setOrderBetJson(resultList.toString());
        vo.setOrderBetList(betList);
    }

    private void getBetInfo_210(UserOrderVO vo, UserOrderPO po, List<UserOrderBetVO> betList){
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("period", vo.getPeriod());
        List<JczqWorldCupPO> cupList=jczqWorldCupMapper.selectList(wrapper);
        Map<String,String> cupMap = new HashMap();
        for(JczqWorldCupPO cup : cupList){
            cupMap.put(cup.getCode()+"",cup.getTeam());
        }
        JSONArray json = new JSONArray();
        Integer status = po.getStatus();
        for (UserOrderBetVO orderBet : betList) {
            String winFlag = "";
            JSONObject betMap = new JSONObject();
            if(!ObjectUtils.isEmpty(orderBet)){
                betMap.put("playType",orderBet.getPlayType().equals("0")?"猜冠军":"猜冠亚军");
                String[] redNums = orderBet.getRedNum().split("\\,");
                String[] odds = orderBet.getBlueNum().split("\\,");
                List<String> _betList = new ArrayList();
                for(int i=0;i<redNums.length;i++){
                    _betList.add(cupMap.get(redNums[i])+"  "+odds[i]);
                }
                betMap.put("betList",_betList);
            }
            if(status==0){
                winFlag = "待付款";
            }
            if(status==2){
                winFlag = "待开奖";
            }
            if(status==3){
                winFlag = "未中奖";
            }
            if(status==4||status==5||status==6){
                winFlag = "已中奖";
            }
            betMap.put("winFlag",winFlag);
            json.add(betMap);
        }
        vo.setOrderBetList(betList);
        vo.setOrderBetJson(json.toString());
    }

    @Override
    public UserOrderVO save(UserOrderVO vo) throws Exception {
        UserOrderPO po = UserOrderO2O.toPO(vo);
        if (StrUtils.isEmpty(vo.getId())) {
            Long id = ymlConfig.getPkId();
            vo.setId(id + "");
            po.setId(id);
            baseMapper.insert(po);
        } else {
            baseMapper.updateById(po);
        }
        return vo;
    }

    @Override
    public UserOrderPO updateCancel(String id,String status) throws Exception {
        UserOrderPO userOrderPO = new UserOrderPO();
        userOrderPO.setId(DispatcherUtils.parseLong(id));
        UserOrderPO po = baseMapper.selectOne(userOrderPO);
        po.setStatus(DispatcherUtils.parseInteger(status));
        baseMapper.updateById(po);
        return po;
    }



    @Override
    public UserOrderVO insertOrder(UserOrderVO vo) throws Exception {
        UserOrderPO po = UserOrderO2O.toPO(vo);
        UserOrderPO _f = baseMapper.getTopUserOrder(po.getUser_id());
        boolean flag = false;
        if (_f == null){
            //胡一刀 判断用户是否是第一次购买，如果是插入活动表
            flag = true;
        }
        if (StrUtils.isEmpty(vo.getId()) && null != vo.getOrderBetList()) {
            Long orderId = ymlConfig.getPkId();
            vo.setId(orderId + "");
            po.setId(orderId);
            //默认未付款状态
            po.setStatus(0);
            //插入跟单表
            if(!StringUtils.isEmpty(vo.getIsPublishFollow()) && "0".equals(vo.getIsPublishFollow())){
                ExpertInfoPO expertInfoPO = expertInfoService.getExpertInfo(Long.valueOf(vo.getUserId()));
                if(expertInfoPO!=null && expertInfoPO.getStatus()==1){
                    FollowOrderPO followOrderPO = new FollowOrderPO();
                    SimpleDateFormat sfDate = new SimpleDateFormat("yyMMddHHmmss");
                    String strDate = sfDate.format(new Date());
                    int random = (int)(Math.random()*(9999-1000+1)+1000);
                    String followOrderId = "tcgd"+strDate+random;
                    followOrderPO.setId(followOrderId);
                    followOrderPO.setUser_id(po.getUser_id());
                    followOrderPO.setOrder_id(po.getId());
                    followOrderPO.setSecrecy_set(Integer.valueOf(vo.getSecrecySet()));
                    followOrderPO.setCommission_rate(new BigDecimal(vo.getCommissionRate()));
                    followOrderPO.setHeel_multiple(Integer.valueOf(vo.getHeelMultiple()));
//                followOrderPO.setGuarantee_odds(Integer.valueOf(vo.getGuaranteeOdds()));
                    followOrderPO.setClose_time(po.getLottery_time());
                    followOrderMapper.insert(followOrderPO);
                    po.setFollow_status(2);
                }
            }
            baseMapper.insert(po);
            for (UserOrderBetVO betVO : vo.getOrderBetList()) {
                UserOrderBetPO bet = UserOrderBetO2O.toPO(betVO);
                bet.setId(ymlConfig.getPkId());
                bet.setOrder_id(orderId);
                bet.setUser_id(po.getUser_id());
                bet.setLottery_id(po.getLottery_id());
                if(po.getLottery_id()==21L || po.getLottery_id()==24L){
                    bet.setPeriod(bet.getPeriod());
                }else{
                    bet.setPeriod(po.getPeriod());
                }
                bet.setBet_times(po.getBet_times());
                //默认待开奖状态
                bet.setStatus(2);
                //根据彩种插入不同投注表
                userOrderBetMapper.insertOrderBet(bet);
            }
            //如果为奖金优化，插入奖金优化投注表
            if(!StringUtils.isEmpty(vo.getIsBonusOptimize()) && "0".equals(vo.getIsBonusOptimize()) && !StringUtils.isEmpty(vo.getBonusOptimizeBetJson())){
                JSONArray bonusOptimizeBetJsonArray = JSONArray.parseArray(vo.getBonusOptimizeBetJson());
                for(int i=0;i<bonusOptimizeBetJsonArray.size();i++){
                    JSONObject bonusOptimizeBetJson = bonusOptimizeBetJsonArray.getJSONObject(i);
                    Integer betTimes = Integer.valueOf((String)bonusOptimizeBetJson.get("betTimes"));
                    JSONArray betList = (JSONArray) bonusOptimizeBetJson.get("betList");
                    BigDecimal sp = new BigDecimal(1);
                    for(int j=0;j<betList.size();j++){
                        JSONObject bet = betList.getJSONObject(j);
                        String redNum = String.valueOf(bet.get("redNum"));
                        String period = String.valueOf(bet.get("period"));
                        JczqMatchVO jczqMatchVO = jczqMatchService.get(period);
                        JSONObject betOddsObj = JSONObject.parseObject(jczqMatchVO.getOdds());
                        BigDecimal betOdds = new BigDecimal((String)betOddsObj.get(redNum));
                        sp = sp.multiply(betOdds);
                    }
                    UserOrderBetBopPO userOrderBetBopPO = new UserOrderBetBopPO();
                    userOrderBetBopPO.setId(ymlConfig.getPkId());
                    userOrderBetBopPO.setUser_id(po.getUser_id());
                    userOrderBetBopPO.setOrder_id(orderId);
                    userOrderBetBopPO.setLottery_id(po.getLottery_id());
                    userOrderBetBopPO.setBet_info(betList.toJSONString());
                    userOrderBetBopPO.setSp(sp);
                    userOrderBetBopPO.setExpect_bonus(sp.multiply(BigDecimal.valueOf(betTimes)).multiply(new BigDecimal(2)));
                    userOrderBetBopPO.setBet_times(betTimes);
                    userOrderBetBopMapper.insert(userOrderBetBopPO);
                }

            }
        }
        return vo;
    }

    @Override
    public Result insertOrderAndPay(UserOrderVO vo) throws Exception {
        Result result = new Result();

        String key = "PAY_DJ_ORDER_"+vo.getUserId();
        String value = stringRedisTemplate.opsForValue().get(key);
        if(StrUtils.isNotEmpty(value)){
            return new Result(CodeEnum.FAIL.getCode(), "您还有未处理的支付订单，请稍后操作！");
        }
        try{
            stringRedisTemplate.opsForValue().set(key, key);
            Map<String, Object> userFundsMap = userFundsMapper.getById(Long.valueOf(vo.getUserId()));
            BigDecimal balance = (BigDecimal) userFundsMap.get("balance");  //中奖趣豆
            BigDecimal lotBean = (BigDecimal) userFundsMap.get("lotBean");  //签到领奖趣豆
            BigDecimal bonus = (BigDecimal) userFundsMap.get("bonus");  //充值趣豆
            BigDecimal subTotal = balance.add(lotBean).add(bonus);  //总余额
            BigDecimal payAmount = new BigDecimal(vo.getPayAmount());   //订单金额
            if (subTotal.compareTo(payAmount) == -1) {
                return new Result(CodeEnum.FAIL.getCode(), "余额不足，请充值！");
            }
            UserOrderPO po = UserOrderO2O.toPO(vo);
            if (StrUtils.isEmpty(vo.getId()) && null != vo.getOrderBetList()) {
                Long orderId = ymlConfig.getPkId();
                vo.setId(orderId + "");
                po.setId(orderId);
                //默认未付款状态
                po.setStatus(0);
                baseMapper.insert(po);
                for (UserOrderBetVO betVO : vo.getOrderBetList()) {
                    UserOrderBetPO bet = UserOrderBetO2O.toPO(betVO);
                    bet.setId(ymlConfig.getPkId());
                    bet.setOrder_id(orderId);
                    bet.setUser_id(po.getUser_id());
                    bet.setLottery_id(po.getLottery_id());
                    if(po.getLottery_id()==21L){
                        bet.setPeriod(bet.getPeriod());
                    }else{
                        bet.setPeriod(po.getPeriod());
                    }
                    bet.setBet_times(po.getBet_times());
                    //默认待开奖状态
                    bet.setStatus(2);
                    //根据彩种插入不同投注表
                    userOrderBetMapper.insertOrderBet(bet);
                }
            }
            userFundsService.payOrder(vo,null);


        }catch(Exception e){
            log.error(vo.getId()+"电竞订单创建失败",e);
        }finally {
            stringRedisTemplate.delete(key);
        }
        result.setData(vo);
        return result;
    }

    @Override
    public void saveOrderTickets(String orderId, String ticketUrls) throws Exception {
        Long _orderId = DispatcherUtils.parseLong(orderId);
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("order_id", _orderId);
        orderTicketMapper.delete(wrapper);
        if (StrUtils.isNotEmpty(ticketUrls)) {
            String[] tickets = ticketUrls.split(",");
            for (String url : tickets) {
                OrderTicketPO po = new OrderTicketPO();
                po.setOrder_id(_orderId);
                po.setTicket_url(url);
                po.setId(ymlConfig.getPkId());
                orderTicketMapper.insert(po);
            }
            UserOrderPO order = new UserOrderPO();
            order.setId(_orderId);
            order.setStatus(2);
            wrapper = new EntityWrapper();
            wrapper.eq("id", _orderId);
            wrapper.le("status", 2);
            baseMapper.update(order, wrapper);
        }
    }


    /***---------------------------------------竞猜计算开始------------------------------------------------*/

    //竞猜计算
    public void updateCalcLottery(Long lotteryId) throws Exception {
        if(lotteryId==21L){
            //足彩计算
            updateCalcFootballAllUserOrder();
        }else {
            LotteryHnumPO lotteryNum = lotteryHnumMapper.getTopOpenForCalc(lotteryId);
            if (null != lotteryNum && 0 == lotteryNum.getCalc_status() && (lotteryNum.getStatus() == 3 || lotteryNum.getStatus() == 4)) {
                updateCalcAllUserOrder(lotteryNum);
            }
        }
    }

    @Override
    //已支付订单取消--通过系统充值红包返现
    public boolean updateOrderCancel(UserOrderPO order){
        //只有付款未出票的订单才能取消
        if(!canBackMoney(String.valueOf(order.getId()))) {
            return false;
        }
        if(2==order.getStatus()&&1==order.getTicket_status()){
            UserCashPO cash = new UserCashPO();
            cash.setId(ymlConfig.getPkId());
            cash.setPay_account("ZQXQ-"+order.getId());
            cash.setPay_amount(order.getPay_amount());
            cash.setUser_id(order.getUser_id());
            cash.setPay_way(0);
            cash.setStatus(4);
            cash.setType(5);
            cash.setAuditor("SYS");
            cash.setInfo("订单取消退款"+order.getPay_amount()+"趣豆");
            UserFundsPO funds = userFundsMapper.selectById(order.getUser_id());
            if(funds != null){
                userCashMapper.insert(cash);
                //退款退回到红包
                userFundsMapper.updateUserBonus(order.getUser_id(),funds.getBonus().add(order.getPay_amount()));
                order.setStatus(7);
                order.setTicket_status(2);
                baseMapper.updateById(order);
                return true;
            }
        }
        log.error("{}订单取消失败。",order.getId());
        return false;
    }


    @Override
    //部分退款
    public synchronized boolean updateOrderBackMoney(String orderId,BigDecimal backMoney){
        if(!canBackMoney(orderId))
            return false;
        UserOrderPO order = baseMapper.selectById(orderId);
        //只有付款未出票的订单才能取消
        UserCashPO cash = new UserCashPO();
        cash.setId(ymlConfig.getPkId());
        cash.setPay_account("ZQXQ-"+order.getId());
        cash.setPay_amount(backMoney);
        cash.setUser_id(order.getUser_id());
        cash.setPay_way(0);
        cash.setStatus(4);
        cash.setType(5);
        cash.setAuditor("SYS");
        cash.setInfo("订单支付失败退款"+backMoney+"趣豆");
        //订单取消
        UserFundsPO funds = userFundsMapper.selectById(order.getUser_id());
        if(funds != null){
            userCashMapper.insert(cash);
            //退款退回到红包
            userFundsMapper.updateUserBonus(order.getUser_id(),funds.getBonus().add(backMoney));
            order.setStatus(7);
            order.setUpdate_time(null);
            baseMapper.updateById(order);
            return true;
        }
        log.error("{}订单取消失败。",order.getId());
        return false;
    }

    @Override
    //退款到余额
    public synchronized boolean backMoneyToBalance(String orderId,BigDecimal backMoney){
        if(!canBackMoney(orderId))
            return false;
        UserOrderPO order = baseMapper.selectById(orderId);
        //只有付款未出票的订单才能取消
        UserCashPO cash = new UserCashPO();
        cash.setId(ymlConfig.getPkId());
        cash.setPay_account("ZQXQ-"+order.getId());
        cash.setPay_amount(backMoney);
        cash.setUser_id(order.getUser_id());
        cash.setPay_way(0);
        cash.setStatus(4);
        cash.setType(5);
        cash.setAuditor("SYS");
        cash.setInfo("订单支付失败退款"+backMoney+"趣豆");
        UserFundsPO funds = userFundsMapper.selectById(order.getUser_id());
        if(funds != null){
            userCashMapper.insert(cash);
            //退款退回到余额
            userFundsMapper.updateUserBalance(order.getUser_id(),funds.getBalance().add(backMoney));
            return true;
        }
        log.error("{}退款到余额失败！",order.getId());
        return false;
    }

    @Override
    public synchronized boolean backMoneyCancelOrder(String orderId){
        if(!canBackMoney(orderId))
            return false;
        UserOrderPO order = baseMapper.selectById(orderId);
        //只有付款未出票的订单才能取消
        UserCashPO cash = new UserCashPO();
        cash.setId(ymlConfig.getPkId());
        cash.setPay_account("ZQXQ-"+order.getId());
        cash.setPay_amount(order.getPay_amount());
        cash.setUser_id(order.getUser_id());
        cash.setPay_way(0);
        cash.setStatus(4);
        cash.setType(5);
        cash.setAuditor("SYS");
        cash.setInfo("订单支付失败退款"+order.getPay_amount()+"趣豆");
        UserFundsPO funds = userFundsMapper.selectById(order.getUser_id());
        if(funds != null){
            userCashMapper.insert(cash);
            //退款退回到余额
            userFundsMapper.updateUserBalance(order.getUser_id(),funds.getBalance().add(order.getPay_amount()));
            order.setStatus(7);
            order.setUpdate_time(null);
            baseMapper.updateById(order);
            return true;
        }
        log.error("{}退款到余额失败！",order.getId());
        return false;
    }

    //检查是否可以退款
    private boolean canBackMoney(String orderId){
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("pay_way",0);
        wrapper.eq("type",5);
        wrapper.eq("pay_account","ZQXQ-"+orderId);
        return userCashMapper.selectCount(wrapper)==0;
    }

    @Override
    public List<UserPrizeVO> queryPrizeList(Long userId) {
        return userPrizeMapper.queryPrizeList(userId);
    }

    @Override
    public Map<String, Object> selectPrizeInfo() {
        return baseMapper.selectPrizeInfo();
    }

    //足彩中奖计算
    @Transactional(rollbackFor = {Exception.class})
    void updateCalcFootballAllUserOrder() throws Exception {
        String key = "CALC_JOB_21";
        String value = stringRedisTemplate.opsForValue().get(key);
        try {
            if (StrUtils.isEmpty(value)) {
                stringRedisTemplate.opsForValue().set(key,key);
                int current = 1, size = 100;
                Page page = new Page(current, size);
                Wrapper wrapper = new EntityWrapper();
                wrapper.eq("lottery_id", 21);
                wrapper.eq("status", 2);
                wrapper.eq("ticket_status", 1);
                wrapper.like("cp", "zqxq", SqlLike.RIGHT);
                wrapper.orderBy("id");
                int total = baseMapper.selectCount(wrapper);
                System.out.println("total:"+total);
                for (; current <= total / size + 1; current++) {
                    page.setCurrent(current);
                    List<UserOrderPO> list = baseMapper.selectPage(page, wrapper);
                    lbl:
                    for (UserOrderPO order : list) {
                        List<UserOrderBetPO> betList = userOrderBetMapper.selectOrderBetList(order.getId(), order.getLottery_id());
                        List<List<Double>> doubleLists = new ArrayList();
                        for (int i = 0; i < betList.size(); i++) {
                            UserOrderBetPO bet = betList.get(i);
                            StringBuffer winInfo = new StringBuffer();
                            Integer status = 3;
                            JczqMatchLiveVO jczqMatchLiveVO = jczqMatchResultService.get(Long.valueOf(bet.getPeriod()));
                            String[] redNums = bet.getRed_num().split("\\,");
                            String[] blueNums = bet.getBlue_num().split("\\,");
                            if (jczqMatchLiveVO == null || jczqMatchLiveVO.getId() == null) {
                                continue lbl;
                            }
                            String[] matchResult = jczqMatchLiveVO.getResult().split("\\,");
                            List<Double> doubleList = new ArrayList();
                            for (int j = 0; j < redNums.length; j++) {
                                for (int k = 0; k < matchResult.length; k++) {
                                    if (redNums[j].equals(matchResult[k])) {
                                        //此号码中奖
                                        status = 4;
                                        winInfo.append(redNums[j] + ",");
                                        String odds = blueNums[j];
                                        doubleList.add(Double.valueOf(odds));
                                    }
                                }
                            }
                            if (!"".equals(winInfo.toString())) {
                                doubleLists.add(doubleList);
                                bet.setWin_info(winInfo.deleteCharAt(winInfo.length() - 1).toString());
                            }
                            bet.setStatus(status);
                            userOrderBetMapper.updateOrderBet(bet);
                        }
                        Double[][] arr = new Double[doubleLists.size()][];
                        for (int i = 0; i < doubleLists.size(); i++) {
                            List<Double> dls = doubleLists.get(i);
                            arr[i] = dls.toArray(new Double[0]);
                        }
                        BigDecimal[] val = FootBallBetUtils.calcWinVal(order.getBet_bunch().split(","), arr, order.getBet_times());
                        BigDecimal rewards = val[0];
                        BigDecimal afterTaxs = val[1];
                        System.out.println("总中奖金额：" + rewards);
                        System.out.println("税后总中奖金额：" + afterTaxs);
                        //足彩中奖后对订单数据进行操作
                        winUserOrder(String.valueOf(order.getId()), rewards, afterTaxs);
                    }
                }
            }

        } catch (Exception e) {
            log.error("计算失败：" + e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); //手动开启事务回滚
        } finally {
            stringRedisTemplate.delete(key);
        }
    }
    @Override
    //足彩中奖后对订单数据进行操作
    public void winUserOrder(String orderId, BigDecimal rewards, BigDecimal afterTaxs) {
        UserOrderPO order = baseMapper.selectById(orderId);
        //订单信息和赛果信息对比，命中信息写到winInfo
        if(rewards.compareTo(BigDecimal.ZERO)==1){
            //订单中奖
            order.setPrize(rewards);
            order.setAfter_tax(afterTaxs);
            if(afterTaxs.compareTo(new BigDecimal("10000"))<=0){
                //税后金额小于等于1万元，自动领奖
                order.setStatus(5);
                if (updateOrderForPrize(order, afterTaxs)) {
                    order.setStatus(6);
                    userOrderBetMapper.updateOrderStatus(21L,order.getId(), 4, 6);
                }
            }else{
                order.setStatus(5);
            }
            order.setWin_time(new Date());
        }else{
            //订单未中奖
            order.setStatus(3);
            /*try {
                long userId = order.getUser_id();
                Wrapper<UserOrderPO> wrapper = new EntityWrapper();
                wrapper.eq("user_id",userId);
                Integer count = userOrderMapper.selectCount(wrapper);
                if (count == 1){
                    //用户首单未中奖
                    SysActivityBO sysActivityBO = new SysActivityBO();
                    sysActivityBO.setActivityId(ActivityIdEnum.ORDER_LOST_PRIZE.getId());
                    sysActivityBO.setOrderId(Long.parseLong(orderId));
                    sysActivityBO.setUserId(userId);
                    sysActivityService.saveUserActivity(sysActivityBO);
                }
            }catch (Exception e){
                log.info("用户首单未中奖ERROR:",e);
            }*/
            order.setWin_time(new Date());
        }
        order.setUpdate_time(null);
        baseMapper.updateById(order);
    }
    //根据采种|期数|用户ID 进行中奖计算
    @Transactional(rollbackFor = {Exception.class})
    void updateCalcAllUserOrder(LotteryHnumPO lotteryNum) throws Exception {
        String key = "CALC_JOB_" + lotteryNum.getLottery_id() + "_" + lotteryNum.getPeriod();
        String value = stringRedisTemplate.opsForValue().get(key);
        try {
            if (StrUtils.isEmpty(value)) {
                log.info("开始计算：" + key);
                stringRedisTemplate.opsForValue().set(key,key);
                int current = 1, size = 100;
                Page page = new Page(current, size);
                Wrapper wrapper = new EntityWrapper();
                wrapper.eq("lottery_id", lotteryNum.getLottery_id());
                wrapper.eq("period", lotteryNum.getPeriod());
                wrapper.eq("status", 2);
                wrapper.eq("ticket_status", 1);
                wrapper.eq("cp", "zqxq");
                wrapper.orderBy("user_id");
                int total = baseMapper.selectCount(wrapper);
                for (; current <= total / size + 1; current++) {
                    page.setCurrent(current);
                    List<UserOrderPO> list = baseMapper.selectPage(page, wrapper);
                    for (UserOrderPO order : list) {
                        updateCalcUserOrder(order, lotteryNum);
                    }
                }
                lotteryNum.setCalc_status(1);
                lotteryHnumMapper.updateById(lotteryNum);
            }
        } catch (Exception e) {
            log.error("计算失败：" + e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); //手动开启事务回滚
        } finally {
            stringRedisTemplate.delete(key);
        }
    }

    //根据单个订单 进行中奖计算
    public void updateCalcUserOrder(UserOrderPO order, LotteryHnumPO lotteryNum) {
        order.setLottery_num(lotteryNum.getRed_num() + "|" + lotteryNum.getBlue_num());
        order.setCreate_time(null);
        order.setUpdate_time(null);
        List<UserOrderBetPO> betList = userOrderBetMapper.selectOrderBetList(order.getId(),lotteryNum.getLottery_id());
        Set<Integer> setStatus = new HashSet();
        //总金额
        BigDecimal prize = new BigDecimal(0);
        //税后金额
        BigDecimal tax = new BigDecimal(0);

        Calculator calculator = null;
        LotteryIdEnum e = LotteryIdEnum.getEnumById(order.getLottery_id());
        switch (e){
            case SSQ:calculator = calculatorSSQ;break;
            case DLT:calculator = calculatorDLT;break;
            case FC:calculator = calculatorFC;break;
            case PL:calculator = calculatorPL;break;
            case QXC:calculator = calculatorQXC;
        }
        for (UserOrderBetPO bet : betList) {
            setStatus.add(caclOrderBet(bet, lotteryNum, calculator));
        }


        //如果订单未领奖
        if (6 != order.getStatus()) {
            //已中奖【人工审核】
            if (setStatus.contains(4)) {
                order.setStatus(5);
                order.setPrize(prize);
                order.setAfter_tax(tax);
            }
            //领奖
            else if (setStatus.contains(5)) {
                order.setStatus(5);
                for (UserOrderBetPO bet : betList) {
                    prize = prize.add(bet.getPrize());
                    tax = tax.add(bet.getAfter_tax());
                }
                order.setPrize(prize);
                order.setAfter_tax(tax);
                if (BigDecimalUtils.bigDecimalToLong(tax) <= 10000L) {
                    if (updateOrderForPrize(order, tax)) {
                        order.setStatus(6);
                        userOrderBetMapper.updateOrderStatus(lotteryNum.getLottery_id(),order.getId(), 5, 6);
                    }
                }
            }
            //未中奖
            else {
                order.setStatus(3);
            }
        }
        baseMapper.updateById(order);
    }


    //计算单注奖金中奖情况  返回每注状态
    private int caclOrderBet(UserOrderBetPO bet, LotteryHnumPO lotteryNumPO, Calculator calculator) {
        Long lotteryId = DispatcherUtils.parseLong(bet.getLottery_id());
        String bettingNum = bet.getRed_num();
        String lotteryNum = lotteryNumPO.getRed_num();
        //如果为双色球与大乐透就组装投注参数
        if(lotteryId == LotteryIdEnum.SSQ.getId()||lotteryId == LotteryIdEnum.DLT.getId()) {
            bettingNum = bet.getRed_num() + "|" + bet.getBlue_num();
            lotteryNum = lotteryNumPO.getRed_num() + "|" + lotteryNumPO.getBlue_num();
        }
        if (StrUtils.isEmpty(bettingNum) || StrUtils.isEmpty(lotteryNum)){
            bet.setStatus(4);
            return bet.getStatus();
        }
        Integer playType = bet.getPlay_type();
        if (playType == null){
            playType = 1;
        }
        String redNum = lotteryNumPO.getRed_num();
        String blueNum = lotteryNumPO.getBlue_num();
        int[] win = calculator.win(lotteryNum, bettingNum, playType+"");
        String winInfo = calculator.winInfo(win, bet.getBet_times());
        bet.setWin_info(winInfo);
        //双色球、大乐透、七星彩的一二等奖直接人工审核
        if ((bet.getLottery_id() == 11L || bet.getLottery_id() == 14L || bet.getLottery_id() ==15L ) && null != win && (win[0] > 0 || win[1] > 0)) {
            win = calculator.win(lotteryNum, bettingNum, bet.getPlay_type().toString());
            winInfo = calculator.winInfo(win, bet.getBet_times());
            bet.setWin_info(winInfo);
            bet.setStatus(4);
        }
        Long amount;
        //状态 0：待付款；1：待出票；2：待开奖；3：未中奖；4：已中奖【人工审核】；5：待领奖；6：已领奖；7：取消，8：支付中
        try {
            amount = DispatcherUtils.parseLong(winInfo);
            bet.setAfter_tax(new BigDecimal(amount));
            if (amount > 0) {
                bet.setPrize(new BigDecimal(amount));
                if (6 != bet.getStatus() || 4 != bet.getStatus()) {
                    bet.setStatus(5);
                }
            } else {
                bet.setStatus(3);
            }
        } catch (Exception e) {
            bet.setStatus(4);
            log.error("计算错误：" + e);
        }
//        userOrderBetMapper.updateById(bet);
        userOrderBetMapper.updateOrderBet(bet);
        return bet.getStatus();
    }

    /**
     * 说    明：   待领奖订单领奖
     * 创 建 人：	一刀·胡
     * 创建时间：	2018/3/28 14:27
     * 修 改 人：
     * 修改日期：
     **/
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public boolean updateOrderForPrize(UserOrderPO order, BigDecimal amount) {
        //只处理待领奖状态
        if (5 == order.getStatus()) {
            //插入 userCash 记录
            UserInfoPO user = userInfoMapper.selectById(order.getUser_id());
            UserFundsPO fund = userFundsMapper.selectById(order.getUser_id());
            fund.setBalance(fund.getBalance().add(amount));
            if (null != fund) {
                UserCashPO cash = new UserCashPO();
                cash.setId(ymlConfig.getPkId());
                cash.setUser_id(order.getUser_id());
                cash.setReal_name(user.getReal_name());
                cash.setMobile(user.getMobile());
                cash.setPay_way(3);
                cash.setPay_account(order.getId() + "");
                cash.setType(3);
                cash.setAuditor("SYS");
                cash.setPay_amount(amount);
                cash.setRemainder(fund.getBalance());
                cash.setStatus(4);
                userCashMapper.insert(cash);
                userFundsMapper.updateUserBalance(fund.getUser_id(), fund.getBalance());
                return true;
            }
            log.info("用户{}资金不存在！");
        } else
            log.info("该订单{} 不能进行领奖，领奖失败！", order.getId());
        return false;
    }

    /**
     * 说    明：   根据采种ID和期数查询
     * 创 建 人：	一刀·胡
     * 创建时间：	2018/3/26 16:48
     * 修 改 人：
     * 修改日期：
     **/
    private List<LotteryHnumPO> selectByLottery(Long lotteryId, String period) {
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("lottery_id", lotteryId);
        wrapper.eq("period", period);
        wrapper.orderBy("create_time", false);
        return lotteryHnumMapper.selectList(wrapper);
    }

    @Override
    public UserOrderVO insertFollowOrder(Long userId,UserOrderVO order, Integer betTimes) {
        UserOrderVO userOrderVO = null;
        order.setUserId(String.valueOf(userId));
        order.setFollowOrderId(order.getId());
        order.setBetTimes(String.valueOf(betTimes));
        Integer betNum = Integer.valueOf(order.getBetNum());
        Integer payAmount = betNum*betTimes*2;
        order.setPayAmount(String.valueOf(payAmount));
        order.setCreateTime(String.valueOf(new Date()));
        order.setUpdateTime(String.valueOf(new Date()));
        order.setId(null);
        order.setFollowStatus("1");
        order.setSecrecySet("3");
        List<UserOrderBetVO> userOrderBetVOList = order.getOrderBetList();
        try {
            for(UserOrderBetVO bet : userOrderBetVOList){
                StringBuffer blueNum = new StringBuffer();
                JczqMatchVO jczqMatchVO = jczqMatchService.get(bet.getPeriod());
                JSONObject betOddsObj = JSONObject.parseObject(jczqMatchVO.getOdds());
                String SelectNumbers = bet.getRedNum();  //选的号
                for(String SelectNumber : SelectNumbers.split(",")){
                    blueNum.append(betOddsObj.get(SelectNumber)+",");
                }
                bet.setBlueNum(blueNum.deleteCharAt(blueNum.length()-1).toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            userOrderVO =  insertOrder(order);
        } catch (Exception e) {
        }
        return userOrderVO;
    }

    @Override
    public Integer getUserTodayPushOrder(Long userId) {
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("user_id",userId);
        wrapper.eq("ticket_status",1);
        wrapper.eq("follow_status",2);
        wrapper.where("date_format(create_time,'%Y-%m-%d')={0}",f.format(new Date()));
        return baseMapper.selectCount(wrapper);
    }
    @Override
    public List<UserOrderVO> getUserTwoDayPushOrder(Long userId) {
        List<UserOrderVO> userOrderVOList = new ArrayList();
        try {
            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DAY_OF_MONTH, -1);
            Date yesterday = c.getTime();
            Wrapper wrapper = new EntityWrapper();
            wrapper.eq("user_id",userId);
            wrapper.eq("ticket_status",1);
            wrapper.eq("follow_status",2);
            wrapper.setSqlSelect("id");
            wrapper.where("date_format(create_time,'%Y-%m-%d')>={0} and date_format(create_time,'%Y-%m-%d')<={1}",f.format(yesterday),f.format(new Date()));
            List<UserOrderPO> userOrderPOList = baseMapper.selectList(wrapper);
            for(UserOrderPO userOrderPO : userOrderPOList) {
                UserOrderVO userOrderVO = getH5(userOrderPO.getId());
                userOrderVOList.add(userOrderVO);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return userOrderVOList;
    }

    @Override
    public String getSP(Long orderId) {
        String SP = "0.00~0.00";
        BigDecimal minSP = BigDecimal.ZERO;
        BigDecimal maxSP = BigDecimal.ZERO;
        try {
            UserOrderVO userOrderVO = get(orderId);
            List<UserOrderBetVO> userOrderBetVOList = userOrderVO.getOrderBetList();
            List<Double[]> list = new ArrayList();
            for(UserOrderBetVO userOrderBetVO : userOrderBetVOList){
                String redNum = userOrderBetVO.getRedNum();
                Map<String,String> oddsMap = new HashMap();
                String[] redNums = userOrderBetVO.getRedNum().split("\\,");
                for (int i=0;i<redNums.length;i++) {
                    oddsMap.put(redNums[i], userOrderBetVO.getBlueNum().split("\\,")[i]);
                }
                Double[] m1 = FootBallBetUtils.getMinMaxOdds(redNum,oddsMap);
                list.add(m1);
            }

            Double minBonus = FootBallBetUtils.betMinVal(userOrderVO.getBetBunch().split(","), list);
            Double maxBonus = FootBallBetUtils.betMaxVal(userOrderVO.getBetBunch().split(","), list);
            minSP = new BigDecimal(minBonus/200).setScale(2,BigDecimal.ROUND_HALF_UP);
            maxSP = new BigDecimal(maxBonus/200).setScale(2,BigDecimal.ROUND_HALF_UP);
            if(minSP.compareTo(maxSP)==0){
                SP = minSP+"";
            }else{
                SP = minSP+"~"+maxSP;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return SP;
    }


}
